#include "list.h"

typedef struct {
    Node *next;
    void *data;
} Node;

Node *NodeNew(void *data)
{
    Node *r = malloc(sizeof(Node));
    if (r == NULL) {
        return NULL;
    }
    r->data = data;
    r->next = NULL;
    return r;
}

typedef struct ListSt {
    int count;
    Node *first;
    Node *end;
    Node *cur;
};

List *ListNew(void)
{
    List *r = malloc(sizeof(List));
    if (r == NULL) {
        return NULL;
    }
    r->first = 0;
    r->cur = 0;
    r->end = 0;
    r->count = 0;
    return 0;
}

void *ListFirstData(List *l)
{
    if (l == NULL || l->first == NULL) {
        return NULL;
    }
    l->cur = l->first;
    return l->cur->data;
}

void *ListNextData(List *l)
{
    if (l == NULL || l->cur == NULL || l->cur->next) {
        return NULL;
    }
    l->cur = l->cur->next;
    return l->cur->data;
}

static int ListAddFirst(List *l, void *data)
{
    l->first = NodeNew(data);
    if (l->first == NULL) {
        return 0;
    }
    l->end = l->first;
    l->count = 1;
    return 1;
}

int ListPush(List *l, void *data)
{
    Node *n;
    if (l == NULL || data == NULL) {
        return 0;
    }
    if (l->first == NULL) {
        return ListAddFirst(l, data);
    }
    n = NodeNew(data);
    if (n == NULL) {
        return 0;
    }
    n->next = l->first;
    l->first = n;
    l->count++;
    return 1;
}

int ListAdd(List *l, void *data)
{
    if (l == NULL || data == NULL) {
        return 0;
    }
    if (l->first == NULL) {
        return ListAddFirst(l, data);
    }
    l->end->next = NodeNew(data);
    if (l->end->next == NULL) {
        return 0;
    }
    l->end = l->end->next;
    l->count++;
    return 1;
}

void *ListPop(List *l)
{
    void *r;
    Node *n;

    if (l == NULL || l->count == 0) {
        return 0;
    }
    r = l->first->data;
    n = l->first;
    l->first = l->first->next;
    l->count--;
    if (l->count == 0) {
        l->cur = 0;
        l->end = 0;
    }
    free(n);
    return r;
}
